#include "YGLog.h"

#include "YGSources.h"
#include "YGString.h"
#include "YGDevice.h"
#include "YGDate.h"
#include "YGFileManager.h"


//#include <stdlib.h>
//#include <string.h>
#include <stdio.h>

namespace YoghurtGum
{

	//extern Log* s_Instance;
	Log* Log::s_Instance = NULL;

	char g_LogLevels[5][6] = {
		"info",
		"trace",
		"error",
		"fatal",
	};

	char g_LogLevelsCap[5][6] = {
		"INFO",
		"TRACE",
		"ERROR",
		"FATAL",
	};

	Log::Log()
	{
		OpenFile();
		Clear();
		SetModule("Main");
		SetFormat("($TIME) - $lEL - $lmsg");
	}

	Log::~Log()
	{

	}

	Log& Log::GetSingleton()
	{
		if (!s_Instance) 
		{
			s_Instance = new Log();

			/**s_Instance << "Opened '" << s_Instance->m_Filename << "' for writing." << ENDL;

#ifdef YG_LOG_EMULATOR

			*s_Instance << "Emulator: Opened '" << s_Instance->m_FilenameEmulator << "' for writing." << ENDL;

#endif*/

		}
		return *s_Instance;
	}

	void Log::SetInstance(Log* a_Instance)
	{
		s_Instance = a_Instance;
	}

	void Log::OpenFile()
	{

#if (YG_OS_TYPE == YG_OS_TYPE_WINDOWSMOBILE)

		char* workingdir = FileManager::Get().GetWorkingDirectory();

		strncat(m_Filename, workingdir, YG_STRLEN(workingdir));

	#ifdef YG_LOG_EMULATOR

		YG_STRCAT(m_FilenameEmulator, 257, "\\Storage Card\\");

	#endif

		YG_STRCAT(m_Filename, 257, "errors_");

	#ifdef YG_LOG_EMULATOR

		YG_STRCAT(m_FilenameEmulator, 257, "emulator_errors_");

	#endif

		char* file = Date::Format("$dd_$mm_$yyyy_$hh_$nn.log");

		strncat(m_Filename, file, YG_STRLEN(file));

		FILE* test;
		test = fopen(m_Filename, "w");
		m_File = test;
		fclose(m_File);

	#ifdef YG_LOG_EMULATOR

		strncat(m_FilenameEmulator, file, YG_STRLEN(file));

		m_FileEmulator = fopen(m_FilenameEmulator, "w");
		fclose(m_FileEmulator);

	#endif

#endif

	}

	void Log::SetFormat(char* a_Format)
	{
		strcpy(m_Format[0], a_Format);
	}

	void Log::SetModule(char* a_ModuleName)
	{
		strcpy(m_Module, a_ModuleName);
	}

	char* Log::Format(char* a_Message, Level a_Level)
	{
		char dated[256] = "";
		strcpy(dated, Date::Format(m_Format[0]));

		memset(m_Formatted, 0, YG_LOG_SIZE);

		int start = 0;
		int length = 0;
		for (unsigned int i = 0; i < strlen(dated); i++)
		{
			if (dated[i] == '$')
			{
				strncat(m_Formatted, &dated[start], length);

				int offset = 0;

				if (!strncmp(&dated[i], "$lel", strlen("$lel")))
				{
					strcat(m_Formatted, g_LogLevels[a_Level]);

					offset = strlen("$lel");
				}
				else if (!strncmp(&dated[i], "$lEL", strlen("$lEL")))
				{
					strcat(m_Formatted, g_LogLevelsCap[a_Level]);

					offset = strlen("$lEL");
				}
				else if (!strncmp(&dated[i], "$lmsg", strlen("$lmsg")))
				{						
					strcat(m_Formatted, a_Message);

					offset = strlen("$lmsg");
				}

				start = i + offset;
				i += offset;
				length = 0;
			}

			length++;
		}

		return m_Formatted;
	}

	void Log::Print(char* a_Message, ...)
	{
		char buffer[2048];

		va_list args;
		va_start(args, a_Message);

#if (YG_OS_TYPE == YG_OS_TYPE_WINDOWSMOBILE)

		vsprintf(buffer, a_Message, args);

#elif (YG_OS_TYPE == YG_OS_TYPE_ANDROID)

		vsprintf(buffer, a_Message, args);

#elif (YG_OS_TYPE == YG_OS_TYPE_BADA)

		vsnprintf(buffer, 256, a_Message, args);

#endif

		va_end(args);

		Output(buffer);
		Clear();
	}

	Log& Log::operator << (LogSpecial a_Special)
	{
		Print(m_Message);
		Clear();

		return GetSingleton();
	}

	void Log::Clear()
	{
		m_Current = 0;
		memset(m_Message, 0, YG_LOG_SIZE);
	}

	void Log::Output(char* a_Message)
	{

		char msg[YG_LOG_SIZE];
		strcpy(msg, Format(a_Message));

#if (YG_OS_TYPE == YG_OS_TYPE_WINDOWSMOBILE)

		printf("%s\n", a_Message);

		//OutputDebugStringA(a_Message);

		/*strcat(msg, "\n");

		m_File = fopen(m_Filename, "a");
		size_t result = fwrite(msg, YG_STRLEN(msg), 1, m_File);
		if (!result)
		{
			//printf("ERROR! Couldn't write to log file! (%s)\n", m_Filename);
		}
		fclose(m_File);

	#ifdef YG_LOG_EMULATOR

		m_FileEmulator = fopen(m_FilenameEmulator, "a");
		fwrite(msg, YG_STRLEN(msg), 1, m_FileEmulator);
		fclose(m_FileEmulator);

	#endif */

#elif (YG_OS_TYPE == YG_OS_TYPE_ANDROID)

		__android_log_print(ANDROID_LOG_INFO, "YoghurtGum", a_Message);

#endif

	}

#if (YG_OS_TYPE == YG_OS_TYPE_WINDOWSMOBILE)

	Log& Log::operator << (wchar_t a_Message)
	{
		char msg[1];
		wcstombs(msg, &a_Message, 1);
		AppendString(msg);

		return GetSingleton();
	}

	Log& Log::operator << (wchar_t* a_Message)
	{
		char* msg = new char[wcslen(a_Message)];
		wcstombs(msg, a_Message, wcslen(a_Message));
		AppendString(msg);

		return GetSingleton();
	}

	Log& Log::operator << (const wchar_t* a_Message)
	{
		char* msg = new char[wcslen(a_Message)];
		wcstombs(msg, a_Message, wcslen(a_Message));
		AppendString(msg);

		return GetSingleton();
	}

	Log& Log::operator << (std::string a_Message)
	{
		AppendString(a_Message.c_str());

		return GetSingleton();
	}

#endif

	Log& Log::operator << (char a_Character)
	{
		AppendString(&a_Character);

		return GetSingleton();
	}

	Log& Log::operator << (float a_Number)
	{
		char number[128];
		YG_SPRINTF(number, 128, "%f", a_Number);
		AppendString(number);

		return GetSingleton();
	}

	Log& Log::operator << (unsigned long a_Number)
	{
		char number[128];
		YG_SPRINTF(number, 128, "%u", a_Number);
		AppendString(number);

		return GetSingleton();
	}

	Log& Log::operator << (int a_Number)
	{
		char number[128];
		YG_SPRINTF(number, 128, "%i", a_Number);
		AppendString(number);

		return GetSingleton();
	}

	Log& Log::operator << (char* a_Message)
	{
		AppendString(a_Message);

		return GetSingleton();
	}

	Log& Log::operator << (const char* a_Message)
	{
		AppendString(a_Message);

		return GetSingleton();
	}



	void Log::AppendString(const char* a_String)
	{
		strcat(&m_Message[m_Current], a_String);
	}

};
